spring cloud alibaba gateway 整合 jwt 实现鉴权 | 您所在的位置:网站首页 › spring security websocket 鉴权 › spring cloud alibaba gateway 整合 jwt 实现鉴权 |
最近在搭建阿里巴巴的微服务框架,这次是引入jwt实现鉴权,主要包括以下功能 (1)登录。接收用户名,密码,校验密码是否正确,若正确则返回token(jwt生成),若错误返回提示信息。 (2)请求网关时校验token。 (3)登出。接收token,将指定token置为失效的状态。 (4)续签。对前端服务部署服务器发过来的请求对过期的token直接返回新的token,并提示更换token。 功能实现涉及两个服务,网关服务,鉴权服务。
一、在鉴权服务中 pom关键配置: 0.11.5 org.springframework.boot spring-boot-starter-web com.auth0 java-jwt 3.10.0 io.jsonwebtoken jjwt-api ${jjwt.version} io.jsonwebtoken jjwt-impl ${jjwt.version} runtime io.jsonwebtoken jjwt-jackson ${jjwt.version} runtime org.springframework.boot spring-boot-starter-data-redis joda-time joda-time 2.9.6
配置文件关键配置: auth: expireMinutes: 20 #过期分钟数 key: 0123456789_0123456789_0123456789 #token生成#省略网关,redis等其他常规设置
工具类(关键代码) package com.example.auth.utils; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.example.auth.constant.JWTConstants; import com.example.auth.model.AuthUser; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.Map; /** * jwt工具类 */ @Component public class JwtUtils { @Value("${auth.expireMinutes:30}") private int expireMinutes; /** * 生成密钥 * * @return 生成密钥 */ Algorithm getAlgorithm() { return Algorithm.HMAC256(JWTConstants.JWT_KEY); } /** * 生成token * * @param userId 用户id * @param userName 用户名 * @param userRole 用户的角色 * @return token jwtToken */ public String generateToken(String userId, String userName, String userRole) { return JWT.create() .withClaim(JWTConstants.JWT_KEY_USER_NAME, userName) .withClaim(JWTConstants.JWT_KEY_ROLE, userRole) .withClaim(JWTConstants.JWT_KEY_ID, userId) .withExpiresAt(DateTime.now().plusSeconds(expireMinutes).toDate()) .sign(getAlgorithm()); } /** * 根据用户信息生成用户 * * @param user 用户信息 * @return token jwtT oken */ public String generateToken(AuthUser user) { return generateToken(user.getId(), user.getUsername(), user.getRole()); } /** * 解码token * * @param token jwtToken * @return 用户信息 */ public AuthUser decode(String token) { AuthUser authUser = new AuthUser(); DecodedJWT decodedJWT = JWT.require(getAlgorithm()).build().verify(token); Map jwt = decodedJWT.getClaims(); String userName = jwt.get(JWTConstants.JWT_KEY_USER_NAME).asString(); String userId = jwt.get(JWTConstants.JWT_KEY_ID).asString(); authUser.setId(userId); authUser.setUsername(userName); return authUser; } }
登录接口 package com.example.auth.controller; import com.alibaba.nacos.common.model.RestResult; import com.example.auth.model.AuthUser; import com.example.auth.model.LoginReturn; import com.example.auth.utils.JwtUtils; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("auth") @RefreshScope public class AuthController { @Resource JwtUtils jwtUtils; @PostMapping("/login") public RestResult login(@RequestBody AuthUser user) { //模拟数据库查询的用户 AuthUser tagetUser = new AuthUser(); tagetUser.setPassword("123456"); //密码校验(demo密码未加密) if (!tagetUser.getPassword().equals(user.getPassword())) { return new RestResult(-1, "用户名与密码不正确"); } String token = jwtUtils.generateToken(user); return new RestResult(1, "认证成功", new LoginReturn(user,token)); } }
其他实体类 ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 二、网关服务 依赖 com.example auth 0.0.1-SNAPSHOT compile org.springframework.boot spring-boot-starter-webJwtTokenFilter 全局过滤器 package com.luoxun.gateway.filter; import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.common.model.RestResult; import com.auth0.jwt.exceptions.TokenExpiredException; import com.example.auth.constant.JWTConstants; import com.example.auth.model.AuthUser; import com.example.auth.utils.JwtUtils; import com.example.auth.utils.RedisUtil; import com.luoxun.gateway.constant.AuthConstant; import com.luoxun.gateway.constant.AuthReturnMessage; import com.luoxun.gateway.constant.BEANOrder; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.annotation.Order; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import javax.annotation.Resource; import java.nio.charset.StandardCharsets; /** * JwtToken 过滤器 */ @Order(BEANOrder.JWT_TOKEN_FILTER) @Component @Slf4j public class JwtTokenFilter implements GlobalFilter { @Value("${auth.tt}") private String skipAuthUrls; @Value("${auth.overduceTime}") private int overdueTime; @Value("${auth.webIp}") private String webIp; @Resource private JwtUtils jwtUtils; @Resource private RedisUtil redisUtil; @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { String url = exchange.getRequest().getURI().getPath(); //跳过不需要验证的路径 if (skipAuthUrls != null && url.equals(skipAuthUrls)) { //继续路由 return chain.filter(exchange); } //获取token String token = exchange.getRequest().getHeaders().getFirst(JWTConstants.JWT_REQUEST_HEADER_KEY); ServerHttpResponse resp = exchange.getResponse(); if (StringUtils.isBlank(token)) { return authError(resp, AuthReturnMessage.AUTH_EXCEPTION_NULL); } else { try { //校验token并解析token AuthUser loginUser = jwtUtils. decode(token); //登出 if (url.equals(AuthConstant.URL_LOGOUT)) { redisUtil.set(AuthConstant.PREFIX_TOKEN_LAPSED + loginUser.getUsername(), token, overdueTime); return authSuccess(resp, AuthReturnMessage.AUTH_SUCCESS_LOGOUT); } //判断token是否已弃用 String sig = redisUtil.get(AuthConstant.PREFIX_TOKEN_LAPSED + loginUser.getUsername()) + ""; if (token.equals(sig)) { return authError(resp, AuthReturnMessage.AUTH_EXCEPTION_LAPSED); } //继续路由 return chain.filter(exchange); } catch (TokenExpiredException tokenExpiredException) { //处理过期的token return expiredToken(tokenExpiredException, exchange, url, token); } catch (Exception e) { log.error(e.getMessage(), e); return authError(resp, AuthReturnMessage.AUTH_EXCEPTION_FAIL); } } } /** * token过期的处理 * * @param tokenExpiredException * @param exchange * @param url * @param token * @return */ private Mono expiredToken(TokenExpiredException tokenExpiredException, ServerWebExchange exchange, String url, String token) { log.error(tokenExpiredException.getMessage(), tokenExpiredException); String userName = exchange.getRequest().getHeaders().getFirst(JWTConstants.JWT_REQUEST_KEY_USER_NAME); String userId = exchange.getRequest().getHeaders().getFirst(JWTConstants.JWT_REQUEST_KEY_ID); String userRole = exchange.getRequest().getHeaders().getFirst(JWTConstants.JWT_REQUEST_KEY_ROLE); ServerHttpRequest request = exchange.getRequest(); String ip = request.getURI().getHost(); ServerHttpResponse resp = exchange.getResponse(); if (webIp.equals(ip)) { //登出 if (url.equals(AuthConstant.URL_LOGOUT)) { return authError(resp, AuthReturnMessage.AUTH_EXCEPTION_EXPIRED); } //判断token是否已弃用 String sig = redisUtil.get(AuthConstant.PREFIX_TOKEN_LAPSED + userName) + ""; if (token.equals(sig)) { return authError(resp, AuthReturnMessage.AUTH_EXCEPTION_EXPIRED); } //续签 String newToken = jwtUtils.generateToken(userId, userName, userRole); return authSuccess(resp, new RestResult(HttpStatus.OK.value(), AuthReturnMessage.AUTH_SUCCESS_TIP_REFRESH, newToken)); } return authError(resp, AuthReturnMessage.AUTH_EXCEPTION_EXPIRED); } /** * 认证错误输出 * * @param resp 响应对象 * @param mess 错误信息 * @return */ private Mono authError(ServerHttpResponse resp, String mess) { resp.setStatusCode(HttpStatus.UNAUTHORIZED); resp.getHeaders().add("Content-Type", "application/json;"); DataBuffer buffer = resp.bufferFactory().wrap(mess.getBytes(StandardCharsets.UTF_8)); return resp.writeWith(Flux.just(buffer)); } private Mono authSuccess(ServerHttpResponse resp, RestResult mess) { resp.setStatusCode(HttpStatus.OK); resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); DataBuffer buffer = resp.bufferFactory().wrap(JSONObject.toJSONString(mess).getBytes(StandardCharsets.UTF_8)); return resp.writeWith(Flux.just(buffer)); } private Mono authSuccess(ServerHttpResponse resp, String mess) { resp.setStatusCode(HttpStatus.OK); resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); DataBuffer buffer = resp.bufferFactory().wrap(mess.getBytes(StandardCharsets.UTF_8)); return resp.writeWith(Flux.just(buffer)); } }
其他 ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]()
|
CopyRight 2018-2019 实验室设备网 版权所有 |